package com.seres.backend.admin;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import com.seres.data.Answer;
import com.seres.data.DataManager;
import com.seres.data.Index;
import com.seres.data.Scenario;
import com.seres.data.Stakeholder;

public class AdminExcelManager {
	private static final String ADMIN_EXCEL_FILE_NAME = "SERES.xlsx";
		
	private static final String STAKEHOLDERS_WORKSHEET = "stakeholders";
	private static final String INDICES_WORKSHEET = "indices";
	private static final String MODULES_WORKSHEET = "modules";
	private static final String MESSAGES_WORKSHEET = "messages";
	private static final String SCENARIOS_AND_ANSWERS_WORKSHEET = "scenarios & answers";
	private static final String ACES_WORKSHEET = "aces";
	private static final String GAME_PARAMETERS_WORKSHEET = "game parameters";
	
	private StakeholdersParserResult stakeholdersParserResult;
	private IndicesParserResult indicesParserResult;
	private ModulesParserResult modulesParserResult;
	private MessagesParserResult messagesParserResult;
	private ScenariosAndAnswersParserResult scenariosAndAnswersParserResult;
	private AcesParserResult acesParserResult;
	private GameParametersParserResult gameParametersParserResult;
	
	private DataManager dataManager;
	
	public static void main(String[] args){
		AdminExcelManager manager = new AdminExcelManager();
		manager.processAdminExcel();
	}
	
	public AdminExcelManager(){
		setDataManager(new DataManager());
	}
	
	public void processAdminExcel(){
		parse();
		updateStakeholderInfo();
		System.out.println();
		performCrossChecks();
		System.out.println();
		store();
	}
	private void updateStakeholderInfo() { //temp method to change the stakeholders regarding the ai input info
		for(int i = 0; i < getStakeholdersParserResult().getStakeholders().size(); i++){
			for(int j = 0; j < getScenariosAndAnswersParserResult().getScenarioBlocks().get(1).getAnswerLines().get(0).getStakeholderIds().size(); j++){
				if(getScenariosAndAnswersParserResult().getScenarioBlocks().get(1).getAnswerLines().get(0).getStakeholderIds().get(j) == getStakeholdersParserResult().getStakeholdersIds().get(i)){
					getStakeholdersParserResult().getStakeholders().get(i).setAiInput(getScenariosAndAnswersParserResult().getScenarioBlocks().get(1).getAnswerLines().get(0).getAiInput().get(j));
				}
			}
		}
	}

	public void parse(){
		
		try {
			
			FileInputStream fileInputStream = new FileInputStream(ADMIN_EXCEL_FILE_NAME);
			XSSFWorkbook workbook = new XSSFWorkbook(fileInputStream);
			XSSFSheet worksheet;
			
			// 1. parse stakeholders
			worksheet = workbook.getSheet(STAKEHOLDERS_WORKSHEET);
			StakeholdersParser stakeholdersParser = new StakeholdersParser(worksheet);
			setStakeholdersParserResult(stakeholdersParser.parse());
			// 2. parse indices
			worksheet = workbook.getSheet(INDICES_WORKSHEET);
			IndicesParser indicesParser = new IndicesParser(worksheet);
			setIndicesParserResult(indicesParser.parse());
			// 3. parse messages
			worksheet = workbook.getSheet(MESSAGES_WORKSHEET);
			MessagesParser messagesParser = new MessagesParser(worksheet, getStakeholdersParserResult().getStakeholdersIds());
			setMessagesParserResult(messagesParser.parse());
			// 4. parse modules
			worksheet = workbook.getSheet(MODULES_WORKSHEET);
			ModulesParser modulesParser = new ModulesParser(worksheet, getStakeholdersParserResult().getStakeholdersIds(), getMessagesParserResult().getMessageIds());
			setModulesParserResult(modulesParser.parse());			
			// 5. parse scenarios & answers
			worksheet = workbook.getSheet(SCENARIOS_AND_ANSWERS_WORKSHEET);
			ScenariosAndAnswersParser scenariosAndAnswersParser = new ScenariosAndAnswersParser(worksheet,getStakeholdersParserResult().getStakeholdersIds());
			setScenariosAndAnswersParserResult(scenariosAndAnswersParser.parse());
			// 6. parse aces
			worksheet = workbook.getSheet(ACES_WORKSHEET);
			AcesParser acesParser = new AcesParser(worksheet,getStakeholdersParserResult().getStakeholdersIds());
			setAcesParserResult(acesParser.parse());
			// 7. parse game parameters
			worksheet = workbook.getSheet(GAME_PARAMETERS_WORKSHEET);
			GameParametersParser gameParametersParser = new GameParametersParser(worksheet);
			setGameParametersParserResult(gameParametersParser.parse());
		}
		catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		
	}
	public void performCrossChecks(){
		for(CoreModuleLine coreModuleLine : getModulesParserResult().getCoreModuleLines()){
			if(!getScenariosAndAnswersParserResult().isExistingCombination(coreModuleLine.getModuleId(), coreModuleLine.getFirstScenarioId())){
				throw new IllegalArgumentException("This core module does not contain an existing first scenario id");
			}
		}
		for(StakeholderModuleLine stakeholderModuleLine : getModulesParserResult().getStakeholderModuleLines()){
			if(!getScenariosAndAnswersParserResult().isExistingCombination(stakeholderModuleLine.getModuleId(), stakeholderModuleLine.getFirstScenarioId())){
				throw new IllegalArgumentException("This stakeholder module does not contain an existing first scenario id");
			}
		}
		for(ScenarioBlock block : getScenariosAndAnswersParserResult().getScenarioBlocks()){
			if(!getModulesParserResult().containsModule(block.getModuleId())){
				throw new IllegalArgumentException("This module id does not exist in the module tab");
			}
			//check if each answer contains a valid next scenario id
			for(AnswerLine answerLine : block.getAnswerLines()){
				if(answerLine.getNextScenarioId() != 0){
					if(!getScenariosAndAnswersParserResult().getScenarioIds().contains(answerLine.getNextScenarioId())){
						throw new IllegalArgumentException("This next scenario id does not exist in the 'scenarios & answers' tab");
					}					
				}

			}
		}
	}
	public void store(){
		//store stakeholders
		HashMap<Integer,Integer> stakeholderIds = storeStakeholders();
		//store indices
		HashMap<Integer,Integer> indexIds = storeIndices();
		//store aces
		storeAces(stakeholderIds);
		//store messages
		HashMap<Integer,Integer> messageIds = storeMessages(stakeholderIds);
		//store scenarios & answers
		HashMap<Integer,Integer> scenarioIds = storeScenariosAndAnswers(stakeholderIds);
		//store modules
		storeModules(messageIds, stakeholderIds, scenarioIds);
	}
	private void storeModules(HashMap<Integer, Integer> messageIds, HashMap<Integer,Integer> stakeholderIds, HashMap<Integer,Integer> scenarioIds) {
		List<Integer> coreModules = new ArrayList<Integer>();
		for(CoreModuleLine coreModuleLine : getModulesParserResult().getCoreModuleLines()){
			coreModules.add(getDataManager().createCoreModule(coreModuleLine.isEvaluationOfRiskIndexIndicator(), coreModuleLine.isEvaluationOfAllStakeholdersIndicator(), null, scenarioIds.get(coreModuleLine.getFirstScenarioId()), coreModuleLine.getTitle()));
		}
		
		List<Integer> riskModules = new ArrayList<Integer>();
		for(RiskModuleLine riskModuleLine : getModulesParserResult().getRiskModuleLines()){
			riskModules.add(getDataManager().createRiskModule(riskModuleLine.isEvaluationOfAllSHIndicator(), messageIds.get(riskModuleLine.getMessageId()), riskModuleLine.getTitle()));
		}
		
		List<Integer> stakeholderModules = new ArrayList<Integer>();
		for(StakeholderModuleLine stakeholderModuleLine : getModulesParserResult().getStakeholderModuleLines()){
			Stakeholder s = getDataManager().readStakeholder(stakeholderIds.get(stakeholderModuleLine.getStakeholderId()));
			stakeholderModules.add(getDataManager().createSHModule(scenarioIds.get(stakeholderModuleLine.getFirstScenarioId()), s, stakeholderModuleLine.getTitle()));
		}
		
		getDataManager().createGameStructure(getModulesParserResult().getGameStructureName(), riskModules, stakeholderModules, coreModules);
		
	}

	private HashMap<Integer,Integer> storeScenariosAndAnswers(
			HashMap<Integer, Integer> stakeholderIds) {
		//hashmap: scenario id from 'scenarios & answers' tab (key) to scenario key from scenario table (value)
		HashMap<Integer,Integer> scenarioIdToKey = new HashMap<Integer,Integer>();
		for(ScenarioBlock block : getScenariosAndAnswersParserResult().getScenarioBlocks()){
			//first create scenarios without answers
			List<Integer> descriptions = new ArrayList<Integer>();
			for(String description : block.getDescriptions()){
				descriptions.add(getDataManager().createDescription(description));				
			}
			List<Integer> images = new ArrayList<Integer>();
			for(String image : block.getImageNames()){
				images.add(getDataManager().createSeresImage(image));
			}
			images.add(getDataManager().createSeresImage(block.getQuestionImageName()));
			
			int scenarioId = getDataManager().createScenario("", descriptions, null, images, block.getQuestion());
			scenarioIdToKey.put(block.getScenarioId(), scenarioId);
			
		}
		//iterate over scenarios and create answers
		for(ScenarioBlock block : getScenariosAndAnswersParserResult().getScenarioBlocks()){
			List<Answer> answers = new ArrayList<Answer>();
			
			for(AnswerLine answerLine : block.getAnswerLines()){
				List<Integer> indexImpacts = new ArrayList<Integer>();
				List<Integer> stakeholderImpacts = new ArrayList<Integer>();
				
				
				Index riskIndex = getDataManager().readIndex("risk");
				indexImpacts.add(getDataManager().createIndexImpact(answerLine.getRiskImpact(), riskIndex));
				
				for(int i = 0; i < answerLine.getImpactScores().size(); i++){
					Stakeholder s = getDataManager().readStakeholder(stakeholderIds.get(answerLine.getStakeholderIds().get(i)));
					stakeholderImpacts.add(getDataManager().createStakeholderImpact(answerLine.getImpactScores().get(i), s));				
				}
				
				int answerId;
				if(answerLine.getNextScenarioId() != 0){
					answerId = getDataManager().createAnswer("", answerLine.getAnswer(), indexImpacts, stakeholderImpacts, false, false, scenarioIdToKey.get(answerLine.getNextScenarioId()));
				}
				else{
					answerId = getDataManager().createAnswer("", answerLine.getAnswer(), indexImpacts, stakeholderImpacts, false, false, 0);
				}
				answers.add(getDataManager().readAnswer(answerId));
			}
			Scenario s = getDataManager().readScenario(scenarioIdToKey.get(block.getScenarioId()));
			s.setPossibleAnswers(answers);
			getDataManager().updateScenario(s);
		}
		return scenarioIdToKey;
	}

	private HashMap<Integer,Integer> storeMessages(HashMap<Integer, Integer> stakeholderIds) {
		//hashmap: message id from 'message' tab (key) to message key from message table (value)
		HashMap<Integer,Integer> messageIdToKey = new HashMap<Integer,Integer>();
		for(MessageLine messageLine : getMessagesParserResult().getMessageLines()){
			List<Integer> indexImpacts = new ArrayList<Integer>();
			List<Integer> stakeholderImpacts = new ArrayList<Integer>();
			
			Index riskIndex = getDataManager().readIndex("risk");
			indexImpacts.add(getDataManager().createIndexImpact(messageLine.getRiskImpact(), riskIndex));
			
			for(int i = 0; i < messageLine.getImpactScores().size(); i++){
				Stakeholder s = getDataManager().readStakeholder(stakeholderIds.get(getMessagesParserResult().getStakeholderIds().get(i)));
				stakeholderImpacts.add(getDataManager().createStakeholderImpact(messageLine.getImpactScores().get(i), s));				
			}
			
			int messageId = getDataManager().createMessage(messageLine.getMessage(), indexImpacts, stakeholderImpacts);
			messageIdToKey.put(messageLine.getMessageId(), messageId);
		}
		return messageIdToKey;
	}

	private void storeAces(HashMap<Integer,Integer> stakeholderIds) {
		HashMap<Integer,List<Integer>> categoryIdToAces = new HashMap<Integer,List<Integer>>();
	
		for(AceLine aceLine : getAcesParserResult().getAceLines()){
			List<Integer> indexImpacts = new ArrayList<Integer>();
			List<Integer> stakeholderImpacts = new ArrayList<Integer>();
			
			Index riskIndex = getDataManager().readIndex("risk");
			indexImpacts.add(getDataManager().createIndexImpact(aceLine.getRiskImpact(), riskIndex));
			
			for(int i = 0; i < aceLine.getImpactScores().size(); i++){
				Stakeholder s = getDataManager().readStakeholder(stakeholderIds.get(aceLine.getStakeholderIds().get(i)));
				stakeholderImpacts.add(getDataManager().createStakeholderImpact(aceLine.getImpactScores().get(i), s));				
			}

			int aceId = getDataManager().createAce(aceLine.getFullDescription(), aceLine.getShortDescription(), indexImpacts, stakeholderImpacts);
			if(categoryIdToAces.containsKey(aceLine.getAceCategoryId())){
				categoryIdToAces.get(aceLine.getAceCategoryId()).add(aceId);
			}
			else{
				List<Integer> aces = new ArrayList<Integer>();
				aces.add(aceId);
				categoryIdToAces.put(aceLine.getAceCategoryId(), aces);
			}
		}
		
		int maxVersionId = getDataManager().readLastAceCategoryVersionId();
		for(AceCategoryLine aceCategoryLine : getAcesParserResult().getAceCategoryLines()){
			getDataManager().createAceCategory(maxVersionId + 1, aceCategoryLine.getAceCategoryName(), categoryIdToAces.get(aceCategoryLine.getAceCategoryId()));
		}
	}

	private HashMap<Integer,Integer> storeStakeholders(){
		int maxVersionId = getDataManager().readLastStakeholderVersionId();
		System.out.println("maxVersionId: " + maxVersionId);
		HashMap<Integer,Integer> stakeholderIds = new HashMap<Integer,Integer>();
		
		for(int i = 0; i < getStakeholdersParserResult().getStakeholders().size(); i++){
			getStakeholdersParserResult().getStakeholders().get(i).setVersionId(maxVersionId + 1);
			int stakeholderId = getDataManager().createStakeholder(getStakeholdersParserResult().getStakeholders().get(i));
			stakeholderIds.put(getStakeholdersParserResult().getStakeholdersIds().get(i), stakeholderId);
			System.out.println("key: " + stakeholderId);
		}
		
		return stakeholderIds;
	}
	private HashMap<Integer,Integer> storeIndices(){
		int maxVersionId = getDataManager().readLastIndexVersionId();
		System.out.println("maxVersionId: " + maxVersionId);
		HashMap<Integer,Integer> indicesIds = new HashMap<Integer,Integer>();
		
		for(int i = 0; i < getIndicesParserResult().getIndices().size(); i++){
			getIndicesParserResult().getIndices().get(i).setVersionId(maxVersionId + 1);
			int indexId = getDataManager().createIndex(getIndicesParserResult().getIndices().get(i));
			indicesIds.put(getIndicesParserResult().getIndicesIds().get(i), indexId);
			System.out.println("key: " + indexId);
		}
		
		return indicesIds;
	}
	public StakeholdersParserResult getStakeholdersParserResult() {
		return stakeholdersParserResult;
	}

	public void setStakeholdersParserResult(
			StakeholdersParserResult stakeholdersParserResult) {
		this.stakeholdersParserResult = stakeholdersParserResult;
	}

	public IndicesParserResult getIndicesParserResult() {
		return indicesParserResult;
	}

	public void setIndicesParserResult(IndicesParserResult indicesParserResult) {
		this.indicesParserResult = indicesParserResult;
	}

	public ModulesParserResult getModulesParserResult() {
		return modulesParserResult;
	}

	public void setModulesParserResult(ModulesParserResult modulesParserResult) {
		this.modulesParserResult = modulesParserResult;
	}

	public MessagesParserResult getMessagesParserResult() {
		return messagesParserResult;
	}

	public void setMessagesParserResult(MessagesParserResult messagesParserResult) {
		this.messagesParserResult = messagesParserResult;
	}

	public ScenariosAndAnswersParserResult getScenariosAndAnswersParserResult() {
		return scenariosAndAnswersParserResult;
	}

	public void setScenariosAndAnswersParserResult(
			ScenariosAndAnswersParserResult scenariosAndAnswersParserResult) {
		this.scenariosAndAnswersParserResult = scenariosAndAnswersParserResult;
	}

	public AcesParserResult getAcesParserResult() {
		return acesParserResult;
	}

	public void setAcesParserResult(AcesParserResult acesParserResult) {
		this.acesParserResult = acesParserResult;
	}

	public GameParametersParserResult getGameParametersParserResult() {
		return gameParametersParserResult;
	}

	public void setGameParametersParserResult(
			GameParametersParserResult gameParametersParserResult) {
		this.gameParametersParserResult = gameParametersParserResult;
	}

	public DataManager getDataManager() {
		return dataManager;
	}

	private void setDataManager(DataManager dataManager) {
		this.dataManager = dataManager;
	}


}
